package com.hyxt.provider;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.hyxt.DTO.DataHandler;
import com.hyxt.DTO.ServerHandler;
import com.hyxt.DTO.protocols.ICase;
import com.hyxt.api.TermianalLinkServer;
import com.hyxt.dao.RedisServiceDAO;
import com.hyxt.utils.xml.XmlElement;
import com.hyxt.utils.xml.XmlException;
import com.hyxt.utils.xml.XmlParser;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.hyxt.DTO.ServerHandler.channleMap;
import static com.hyxt.DTO.ServerHandler.signMap;

import static com.hyxt.DTO.TermianaUtil.findIpAndPort;

/**
 * @author shenp
 * @version v1.0
 * @Description：终端链路服务端管理
 * @Date: Create in 14:39 2017/11/21
 * @Modifide By:
 **/
@Service(interfaceClass = TermianalLinkServer.class,version = "1.0.0")
public class TermianalLinkServerImpl implements TermianalLinkServer {
    /**
     * 日志
     */
    /*private static Logger log = LoggerFactory.getLogger();*/
    private static Log log = LogFactory.getLog(TermianalLinkServerImpl.class
            .getName());
    /**
     * 配置文件对象
     */
    private XmlElement xmlElement;
    /**
     * 数据处理类
     */
    private DataHandler handle;
    /**
     * 选择器集合
     */
    List<Map> caseList = null;
    @Reference(version = "1.0.0")
    RedisServiceDAO redisServiceDAO;
    @Override
    public boolean startServer(List list) {
        log.debug("netty tcp socketserver starting...");
        //初始化配置文件
        init();
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        // 实例化一下bootstrap
        ServerBootstrap bootstrap = new ServerBootstrap();
        // 给group赋值
        bootstrap.group(bossGroup, workerGroup);
        // 配置channel
        bootstrap.channel(NioServerSocketChannel.class);
        bootstrap.option(ChannelOption.SO_RCVBUF, 2048)
                .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(4096, 8192, 65535));
        bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                // 过滤编码
                pipeline.addLast("decoder", new ByteArrayDecoder());
                // 过滤编码
                pipeline.addLast("encoder", new ByteArrayEncoder());
                // 设置接收消息的处理类
                pipeline.addLast("Process", new ServerHandler(handle,redisServiceDAO));
            }
        });
            // 循环绑定，找到可用端口 portlist
            for (int j = 0; j < list.size(); j++) {
                // 获取端口号
                int port = (int) list.get(j);
                try {
                    // 绑定IP 和端口
                    bootstrap.bind(port).sync();
                    // log
                    log.info("绑定端口成功,port:" + port);
                    // 跳出循环
                    break;
                } catch (Exception e) {
                    // log
                    log.error("绑定端口失败,port:" + port);
                    continue;
                }
            }
        return true;
    }

    /**
     * 销毁链路
     * @param sign 终端唯一标识
     * @return
     */
    @Override
    public boolean deleteChannel(String sign) {
        String ipAndPort = findIpAndPort(sign);
        signMap.remove(sign);
        if (!"".equals(ipAndPort)){
            //关闭链路
            channleMap.get(ipAndPort).close();
            //移除缓存
            channleMap.remove(ipAndPort);
            log.info("链路销毁成功");
            return true;
        }else {
            log.info("链路销毁失败");
            return false;
        }
    }

    /**
     * 查找链路
     * @param sign 终端唯一标识
     * @return
     */
    public Channel findChannel(String sign) {
        String ipAndPort = findIpAndPort(sign);
        if (!"".equals(ipAndPort)){
            return channleMap.get(ipAndPort);
        }
        return null;
    }

    /**
     * 发送数据
     * @param sign 终端唯一标识
     * @param bytes 需要发送数据
     * @return
     */
    @Override
    public boolean sendMessage(String sign, byte[] bytes) {
        //根据唯一标识获取ip+port
        String ipAndPort = findIpAndPort(sign);
        if (!"".equals(ipAndPort)){
            //获取链路
            Channel channel = channleMap.get(ipAndPort);
            if(channel!=null){
                //发送数据
                channel.writeAndFlush(bytes);
                return true;
            }
        }
        return false;
    }

    /**
     * 初始化协议类型
     * @return
     */
    public boolean init(){
        try{
            String param = "src/main/resources/protocols.xml";
            xmlElement = new XmlParser(new FileReader(param)).parse();
        }catch (FileNotFoundException e){
            return false;
        }catch (XmlException e){
            log.warn("", e);
            return false;
        }
            caseList = new ArrayList<Map>();
            // 从配置文件取出case标签
            List<XmlElement> sList = xmlElement.getChildElements("case");
            for (XmlElement xmlElement : sList) {
                ICase CaseHandler = null;
                try {
                    // 根据协议名称实例化处理类
                    CaseHandler = (ICase) Class.forName(xmlElement.getAttribute("casename")).newInstance();
                } catch (InstantiationException e) {
                    // 打印异常
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // 打印异常
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    // 打印异常
                    e.printStackTrace();
                }
                // new一个map
                Map<String, Object> map = new HashMap<String, Object>();
                // 把选择器放到map里
                map.put("case", CaseHandler);
                // 把协议名字放到map里
                map.put("name", xmlElement.getAttribute("name"));
                // 把map放到list里
                caseList.add(map);
            }
            // 实例化处理类
            handle = new DataHandler();
            handle.init(caseList);
            return true;
    }

}
